package owg.util.editor2d.operations;

import owg.util.data.PFieldElement;
import owg.util.data.KryoInstance.K;
import owg.util.editor2d.Editor2D;
/**The opposite part of the {@link LinkOperation} transaction.
 * Note that this cannot be used to break links, it can only be used to undo them.*/
public class UnlinkOperation extends Operation
{
	private LinkOperation companion;
	@K private UnlinkOperation(){}
	/**Create a new unlinker for the associated linker operation.
	 * The reference to the linker is needed to obtain specific information that is not available until the linking has been executed.*/
	public UnlinkOperation(LinkOperation companion)
	{
		this.companion = companion;
	}
	
	@Override
	public void apply(Editor2D w) throws OperationFailedException
	{
		if(companion.srcObject == null)
			throw new OperationFailedException(this+" could not be applied because the linker has not been sucessfully executed!");
		
		//Use a two-way handshake:
		//Connect/disconnect one way, remembering original value
		//Connect/disconnect other way
		//If error occurs after first connect/disconnect, 
		//then restore the remembered value, hopefully doing as little damage as possible.
		PFieldElement srcConnectorRestoreValue = null;
		boolean srcConnectorCompleted = false;
		try {
			if(companion.srcConnectorRestoreValue == null)
			{
				companion.srcConnector.remove(companion.dstObject);
			}
			else
			{
				srcConnectorRestoreValue = companion.srcConnector.get();
				companion.set(companion.srcConnector, companion.srcConnectorRestoreValue);
			}
			srcConnectorCompleted = true;

			if(companion.dstConnectorRestoreValue == null)
			{
				companion.dstConnector.remove(companion.srcObject);
			}
			else
			{
				companion.set(companion.dstConnector, companion.dstConnectorRestoreValue);
			}
		}
		catch(Exception e)
		{
			if(srcConnectorCompleted)
			{
				//Note: if an error occurs here, we are boned.
				//Can't really do anything about that except fix the application.
				if(srcConnectorRestoreValue == null)
					companion.srcConnector.remove(companion.dstObject);
				else
					companion.set(companion.srcConnector, srcConnectorRestoreValue);
					
			}
			throw new OperationFailedException("Unlinking failed!", e);
		}
	}
}